#pragma once 
#include <memory>
#include <unordered_map>
#include <ostream>

#include <functional>

namespace frame {
namespace imp {


class Timer;
class ITimerTask {
public:
    ITimerTask(uint64_t timerId = 0)
    :timerId(timerId)
    {
    }
    uint64_t getTimerId() const {
        return timerId;
    }
    void setTimerId(uint64_t timerId) {
        this->timerId = timerId;
    }

    virtual ~ITimerTask(){};
    virtual void handle(Timer * timer) = 0;
private:
    uint64_t timerId;
};


class Timer{
public:
    Timer(uint64_t id, ITimerTask * task, uint64_t timespan)
    :id(id), task(task), timespan(timespan)
    {
    }
    virtual ~Timer(){
    }

    uint64_t getId()const {
        return id;
    }
    ITimerTask * getTimerTask() const {
        return  task;
    }
    uint64_t getTimeSpan() const {
        return timespan;
    }

    virtual void startTimer() = 0;
    virtual void stopTimer() = 0;

private:
    uint64_t id;
    ITimerTask * task;
    uint64_t timespan; //ms
};

std::ostream & operator << (std::ostream & os, const Timer & time);


class TimerTasks{
public:
    virtual ~TimerTasks(){
    }

    size_t size() const { 
        return timerTasks.size();
    }
    bool contains(int timerId) const{
        return timerTasks.find(timerId) != timerTasks.end();
    }

    std::shared_ptr<Timer> remove(uint64_t timerId);
    std::shared_ptr<Timer> getTimer(int timerId) const;

    // for loop
    typedef std::unordered_map<uint64_t, std::shared_ptr<Timer>>  TimerMap;
    typedef TimerMap::const_iterator  const_iterator;
    const_iterator begin() const noexcept{
        return timerTasks.cbegin();
    }
    const_iterator end() const noexcept{
        return timerTasks.cend();
    }
protected:
    void insertNoFind(std::shared_ptr<Timer> timer);
    bool insert(std::shared_ptr<Timer> timer);

private:
    TimerMap timerTasks;
};



} //end of namespace imp
} //end of namespace  frame
